package com.hsogoo.avatar.proxy;


import java.lang.reflect.Method;

import org.apache.commons.lang.StringUtils;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import com.hsogoo.avatar.AvatarClient;
import com.hsogoo.avatar.control.FallBack;
import com.hsogoo.avatar.control.LimitControl;
import com.hsogoo.avatar.enums.Protocol;
import com.hsogoo.avatar.exceptions.AvatarException;
import com.hsogoo.avatar.model.AvatarAddress;
import com.hsogoo.avatar.model.AvatarRequest;
import com.hsogoo.avatar.model.AvatarResponse;
import com.hsogoo.avatar.model.InvokeMethod;
import com.hsogoo.avatar.processor.DefaultAvatarProcessor;
import com.hsogoo.avatar.registry.AvatarRegistry;
import com.hsogoo.avatar.registry.InvokeMethodRegistry;
import com.hsogoo.avatar.registry.LimitControlRegistry;
import com.hsogoo.avatar.registry.RegistryProvider;
import com.hsogoo.avatar.registry.ServiceMeta;
import com.hsogoo.avatar.sequence.DefaultKeyGenerator;
import com.hsogoo.avatar.transport.AvatarConnector;
import com.hsogoo.avatar.transport.netty.AvatarNettyConnector;

import lombok.extern.slf4j.Slf4j;

/**
 * 通过cglib生成动态代理拦截带AvatarInvoke注解的对象的方法
 * @Author huangsaigang
 * Created @2018/9/25.
 */
@Slf4j
public class DefaultAvatarProxyFactory implements AvatarProxyFactory {

    private static class AvatarProxyFactoryHolder{
        private static final DefaultAvatarProxyFactory instance = new DefaultAvatarProxyFactory();
    }

    private DefaultAvatarProxyFactory(){}

    public synchronized static DefaultAvatarProxyFactory getInstance(){
        return AvatarProxyFactoryHolder.instance;
    }

    @Override
    public Object createProxy(Class clazz) throws Exception {
        Enhancer enhancer = new Enhancer();
        enhancer.setInterfaces(new Class[]{clazz});
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                InvokeMethod invokeMethod = InvokeMethodRegistry.getInvokeMethod(method);
                String interfaceName = invokeMethod.getClassName();
                String methodName = method.getName();
                long timeout = invokeMethod.getTimeout();
                log.info("avatar invoke {}.{}", interfaceName, methodName);

                LimitControl limitControl = LimitControlRegistry.getLimitControl(interfaceName);
                //未通过client限流
                if(limitControl != null && !limitControl.tryAcquire(timeout)){
                    FallBack consumerFallback = FallBack.Default;
                    String fallback = invokeMethod.getFallback();
                    if(StringUtils.isNotBlank(fallback)){
                        try{
                            Class clazz = Class.forName(fallback);
                            consumerFallback = (FallBack) clazz.newInstance();
                        }catch (Exception e){
                            log.error(String.format("fallback {%s} create Exception, use default fallback", fallback));
                        }
                    }
                    AvatarResponse response = consumerFallback.invoke();
                    if(response.isSuccess()){
                        return response.getResult();
                    }else{
                        throw new AvatarException(String.format("AvatarException resultCode=[%s], resultMessage=[%s]", response.getResultCode(), response.getResultMessage()));
                    }
                }

                //构建request
                AvatarRequest request = new AvatarRequest();
                request.setRequestId(String.valueOf(new DefaultKeyGenerator().generateSequence()));
                request.setInterfaceName(interfaceName);
                request.setMethodName(methodName);
                request.setArgTypes(invokeMethod.getArgTypes());
                request.setArgs(args);
                request.setTimeout(timeout);
                request.setProtocol(Protocol.AVATAR);

                //构建avatarClient
                AvatarConnector connector = new AvatarNettyConnector(Protocol.AVATAR).withProcessor(new DefaultAvatarProcessor());
                AvatarRegistry registry = RegistryProvider.getRegistry(invokeMethod.getRegistry());
                AvatarClient avatarClient = new AvatarClient().withRegistry(registry).withConnector(connector);

                //构建serviceMeta
                ServiceMeta serviceMeta = new ServiceMeta();
                serviceMeta.setGroup(invokeMethod.getGroup());
                serviceMeta.setServiceProviderName(interfaceName);
                serviceMeta.setVersion(invokeMethod.getVersion());

                //获取provider地址
                AvatarAddress providerAddress = avatarClient.lookup(serviceMeta);
                if (providerAddress == null) {
                    throw new AvatarException(String.format("AvatarException no provider find for [%s]", serviceMeta.toString()));
                }

                //发送请求到provider对应的服务端并获取返回结果
                AvatarResponse response = avatarClient.sendRequest(providerAddress, request);
                if(response.isSuccess()){
                    return response.getResult();
                }else{
                    throw new AvatarException(String.format("AvatarException resultCode=[%s], resultMessage=[%s]", response.getResultCode(), response.getResultMessage()));
                }
            }
        });
        return enhancer.create();
    }

}
